// Shape class - base class for all scene elements
function Shape(options){
	//unique id of the shape
	this.id = new Date().getTime();
	
	// declare shape position, width and height - used to compute the shape boundary
	// shape boundary is used to determine what region on the screen is redrawn when something changes
	this.x = 0;
	this.y = 0;
	this.w = 0;
	this.h = 0;
	
	// shape boundary - initialized with 0. Each shape type will be responsible to set it's own boundaries.
	this.boundary = {x:0,y:0,w:0,h:0};
	// setter for boundary - this function will be used by child shapes to set their own boundaries
	this.updateBoundary = function(x,y,w,h){
		x = x | this.x-this.strokeWidth;
		y = y | this.y - this.strokeWidth;
		w = w | this.w + this.strokeWidth + this.strokeWidth;
		h = h | this.h + this.strokeWidth + this.strokeWidth;
		this.boundary = {x:x,y:y,w:w,h:h};
	};
	
	// specifies whether this shape is sensible to mouse events (down, up, move)
	// if false, mouse events will not affect or call the shape's handlers
	this.ignoreMouseEvents = true;
	
	this.allowMouseEvents = function(){
		return !this.ignoreMouseEvents;
	}
	
	this.allowMouseDownEvent = function(){
		return !this.ignoreMouseEvents;
	}
	
	// shape depth paramater - the bigger zIndex, the closer to the user the shape is. Allows us to specify which shape is on top and which is on bottom.
	this.zIndex = 1;
	
	// drawing properties for drawed shapes (circle, line, etc), and text properties
	this.strokeColor = "#000";
	this.strokeWidth = 1;
	this.fillColor = null;
	this.fontFamily = "Arial";
	this.fontSize = 12;
	
	this.fill = false; // specifies whether to fill or to draw
	
	// sets the style of the shape for drawing, setting up the drawing color, and width
	this.setFillStyles = function(ctx){
		if(this.fill){
			ctx.lineWidth = this.strokeWidth;
			if(this.fillColor) ctx.fillStyle = this.fillColor;
			else{
				ctx.fillStyle = null;			
			}
		}
	}
	this.setStrokeStyles = function(ctx){
		ctx.lineWidth = this.strokeWidth;
		if(!this.strokeWidth || this.strokeWidth<=0){
			ctx.strokeStyle = null;
		}
		else ctx.strokeStyle = this.strokeColor;
	}
	this.setStyles = function(ctx){
 		ctx.lineWidth = this.strokeWidth;
		ctx.strokeStyle = this.strokeColor;			
		if(this.fillColor) ctx.fillStyle = this.fillColor;
		else{
			ctx.fillStyle = null;			
		}
		//if(this.type=="circle") console.log(this.strokeColor+" "+ctx.strokeStyle+"     "+this.fillColor+" "+ctx.fillStyle);		
	};
	
	// executes the draw
	// each shape will draw itself, but will need to call this function to actually write themselves on the scene
	this.executeDraw = function(ctx){
		//this.setStyles(ctx);	
		this.setFillStyles(ctx);
		this.setStrokeStyles(ctx);
		if(this.fill){
			ctx.fill();
		}
		if(this.strokeWidth && this.strokeWidth>0 || !this.fill){
			
			ctx.stroke();
		}
	};
	
	// list of sub-shapes
	// each shape can contain child shapes, the shape specific type will be responsible for handling how these are drawn
	this.shapes = new Array();
	// The parent scene. All shapes will need a pointer to the parent scene. This attribute is set in the add shape function, and 
	// will be cleared in the remove shape functions.
	this.scene = null;
	
	// virtual function for draw, each shape type will need to override this to draw itself
	this.draw = function(context){
	};
	
	// moves the shape to a new position, this function causes an invalidation, that will trigger redrawing of the shape in the new position,
	// and redrawing of all other shapes that intersect it's boundaries
	this.move = function(x,y){
		this.x = x;
		this.y = y;
		this.invalidate();
	}
	
	// resizes the shape to a new size, this function also causes invalidation
	this.resize = function(w,h){
		this.w = w;
		this.h = h;
		this.invalidate();
	}
	
	// ads a new shape to the child shapes list
	this.add = function(shape){
		this.shapes.push(shape);
		shape.scene = this.scene;
		if(shape.addedToScene) shape.addedToScene(this.scene);
		return shape;
	};
	// removes a shape from the child shapes list
	this.remove = function(shape){
		for(var i=0;i<this.shapes.length;i++){
			if(this.shapes[i]==shape){
				this.shapes.splice(i,1);
				shape.scene = null;
				return shape;
			}
		}
	};
	// removes the shape ad the specified index
	this.removeAt = function(idx){
		if(this.shapes.length>idx){
			this.shapes[idx].scene = null;
			this.shapes.splice(idx,1);
		}
	};
	
	this.addedToScene = function(scene){
	}
	
	// checks if the shape intersects the specified boundary
	this.intersectsBoundary = function(scene, boundary){
		return scene.domUtils.boundariesIntersect(this.boundary, boundary);
	}
	
	// invalidates this shape
	// this triggers redrawing of itself and everything intersecting its boundary
	this.invalidate = function(){
		if(!this.scene)return;
		// invalidates original boundary
		this.scene.invalidate({boundary : this.boundary,shape: this});
		
		// recompute boundaries 
		this.updateBoundary();
		
		// invalidates the new boundary
		this.scene.invalidate({boundary : this.boundary});
	}
	
	// basic mouse down event of the shape
	// this will be triggered when the user presses the mouse on it
	this.mouseDown = function(pos){
		console.log("Down on "+this.id);
	}
	// basic mouse up event
	// this will be triggered whenever the user releases the mouse button (on it or on other element)
	this.mouseUp = function(pos){
		console.log("Up on "+this.id);
	}
	// basic mouse move event
	// this will be triggered when the user moves the mouse over the scene
	this.mouseMove = function(pos){
		console.log("mouse move");
	}
}